package coupon

import (
	"fmt"
	"time"
	// "bp/cache"
	sqlc "bp/db/sqlc"
	"bp/db/sqlc/ctype"
	"bp/internal/util"
	"context"
	"database/sql"
)

// CreateCoupon 新建优惠券参数
type CreateCouponParam struct {
	CreateCouponParamsPtr *sqlc.CreateCouponParams
}

// CreateCoupon 新建优惠券
func (s *CouponEntityServiceImp) CreateCoupon(ctx context.Context, q *sqlc.Queries, ptr *CreateCouponParam) (
	couponPtr *sqlc.Coupon,
	err error) {
	slog := util.NewContextLogger(ctx, s.slog)

	coupon, err := q.CreateCoupon(ctx, *ptr.CreateCouponParamsPtr)
	if err != nil {
		return
	}
	slog.Infof("1 CreateCoupon ok")

	couponPtr = &coupon
	return
}

// UpdateCouponParam 更新优惠券参数
type UpdateCouponParam struct {
	CouponID                int64
	Name                    string
	Desc                    string
	Tags                    []string
	OfferCategory           string
	OfferType               string
	Bg                      string
	NeedVerifyQualification bool
	QualifyTypes            []string
	Price                   int32
	Quota                   int32
	OffMaximum              int32
	UsePeriodType           string
	Days                    int32
	AvailableAfterGotDays   int32
	UseBegined              time.Time
	UseEnded                time.Time
	UseTimeRanges           ctype.TimeRangeArray
	DateChooseType          string
	Weekdays                []int32
	Monthdays               []int32
	UseScenes               []string
	Scope                   string
	Maximum                 int32
	MaxiumGotFrequency      int32
}

// UpdateCoupon 更新优惠券
func (s *CouponEntityServiceImp) UpdateCoupon(ctx context.Context, q *sqlc.Queries, ptr *UpdateCouponParam) (
	couponPtr *sqlc.Coupon,
	err error) {
	slog := util.NewContextLogger(ctx, s.slog)

	couponID := ptr.CouponID
	couponPtr, err = s.GetCouponPtr(ctx, q, couponID)
	if err != nil {
		if sql.ErrNoRows == err {
			err = fmt.Errorf("无法找到要更新的券")
		}
		return
	}
	slog.Infof("1 GetCouponPtr ok")

	isAnyoneGot, err := q.CheckIsAnyoneGotByCouponID(ctx, couponID)
	if err != nil {
		return
	}
	slog.Infof("2 CheckIsAnyoneGotByCouponID=>%v ok", isAnyoneGot)

	var coupon sqlc.Coupon
	if isAnyoneGot {

		// 思考?已发布到会员侧的券,修改品牌或商品必须增加
		if couponPtr.Maximum > ptr.Maximum {
			err = fmt.Errorf("更新的券最大数必须大于现有的最大数")
			return
		}
		coupon, err = q.UpdateCouponWithDistributed(ctx, sqlc.UpdateCouponWithDistributedParams{
			ID:                      couponID,
			Name:                    ptr.Name,
			Desc:                    sqlc.NSFromString(ptr.Desc),
			Tags:                    ptr.Tags,
			Bg:                      sqlc.NSFromString(ptr.Bg),
			NeedVerifyQualification: ptr.NeedVerifyQualification,
			QualifyTypes:            ptr.QualifyTypes,
			Maximum:                 ptr.Maximum,
			MaxiumGotFrequency:      ptr.MaxiumGotFrequency,
		})
	} else {
		coupon, err = q.UpdateCouponWithoutDistributed(ctx, sqlc.UpdateCouponWithoutDistributedParams{
			ID:                      couponID,
			Name:                    ptr.Name,
			Desc:                    sqlc.NSFromString(ptr.Desc),
			Tags:                    ptr.Tags,
			OfferCategory:           ptr.OfferCategory,
			OfferType:               ptr.OfferType,
			Bg:                      sqlc.NSFromString(ptr.Bg),
			NeedVerifyQualification: ptr.NeedVerifyQualification,
			QualifyTypes:            ptr.QualifyTypes,
			Price:                   ptr.Price,
			Quota:                   ptr.Quota,
			OffMaximum:              ptr.OffMaximum,
			UsePeriodType:           ptr.UsePeriodType,
			Days:                    sqlc.NInt32FromInt32(ptr.Days),
			AvailableAfterGotDays:   sqlc.NInt32FromInt32(ptr.AvailableAfterGotDays),
			UseBegined:              sqlc.NTimeFromTime(ptr.UseBegined),
			UseEnded:                sqlc.NTimeFromTime(ptr.UseEnded),
			UseTimeRanges:           ptr.UseTimeRanges,
			DateChooseType:          sqlc.NSFromString(ptr.DateChooseType),
			Weekdays:                ptr.Weekdays,
			Monthdays:               ptr.Monthdays,
			UseScenes:               ptr.UseScenes,
			Scope:                   ptr.Scope,
			Maximum:                 ptr.Maximum,
			MaxiumGotFrequency:      ptr.MaxiumGotFrequency,
		})
	}
	if err != nil {
		return
	}
	slog.Infof("3 UpdateCoupon ok")

	couponPtr = &coupon
	return
}

// UpdateCouponStatusParam 更新优惠券状态参数
type UpdateCouponStatusParam struct {
	CouponPtr *sqlc.Coupon
	CouponID  int64
}

// PublishCoupon 发布优惠券
func (s *CouponEntityServiceImp) PublishCoupon(ctx context.Context, q *sqlc.Queries, ptr *UpdateCouponStatusParam) (couponPtr *sqlc.Coupon, err error) {
	slog := util.NewContextLogger(ctx, s.slog)

	if ptr.CouponPtr != nil {
		couponPtr = ptr.CouponPtr
	} else {
		couponPtr, err = s.GetCouponPtr(ctx, q, ptr.CouponID)
		if err != nil {
			if sql.ErrNoRows == err {
				err = fmt.Errorf("无法找到要发布的优惠券")
			}
			return
		}
		slog.Infof("0 GetCouponPtr ok")
	}
	if couponPtr.CouponStatus != string(sqlc.EmCouponStatusDraft) {
		err = fmt.Errorf("优惠券状态不匹配")
		return
	}
	couponID := couponPtr.ID

	err = q.PublishCoupon(ctx, couponID)
	if err != nil {
		return
	}
	couponPtr.CouponStatus = string(sqlc.EmCouponStatusPublished)
	couponPtr.Published = sqlc.NTimeFromTime(time.Now())
	slog.Infof("1 PublishCoupon ok")

	return
}

// PauseCoupon 暂停优惠券
func (s *CouponEntityServiceImp) PauseCoupon(ctx context.Context, q *sqlc.Queries, ptr *UpdateCouponStatusParam) (couponPtr *sqlc.Coupon, err error) {
	slog := util.NewContextLogger(ctx, s.slog)

	if ptr.CouponPtr != nil {
		couponPtr = ptr.CouponPtr
	} else {
		couponPtr, err = s.GetCouponPtr(ctx, q, ptr.CouponID)
		if err != nil {
			if sql.ErrNoRows == err {
				err = fmt.Errorf("无法找到要暂停的优惠券")
			}
			return
		}
		slog.Infof("0 GetCouponPtr ok")
	}
	if couponPtr.CouponStatus != string(sqlc.EmCouponStatusPublished) {
		err = fmt.Errorf("优惠券状态不匹配")
		return
	}
	couponID := couponPtr.ID

	err = q.PauseCoupon(ctx, couponID)
	if err != nil {
		return
	}
	couponPtr.CouponStatus = string(sqlc.EmCouponStatusPaused)
	couponPtr.Paused = sqlc.NTimeFromTime(time.Now())
	slog.Infof("1 PauseCoupon ok")

	return
}

// PauseCoupon 恢复优惠券
func (s *CouponEntityServiceImp) ResumeCoupon(ctx context.Context, q *sqlc.Queries, ptr *UpdateCouponStatusParam) (couponPtr *sqlc.Coupon, err error) {
	slog := util.NewContextLogger(ctx, s.slog)

	if ptr.CouponPtr != nil {
		couponPtr = ptr.CouponPtr
	} else {
		couponPtr, err = s.GetCouponPtr(ctx, q, ptr.CouponID)
		if err != nil {
			if sql.ErrNoRows == err {
				err = fmt.Errorf("无法找到要恢复的优惠券")
			}
			return
		}
		slog.Infof("0 GetCouponPtr ok")
	}
	if couponPtr.CouponStatus != string(sqlc.EmCouponStatusPaused) {
		err = fmt.Errorf("优惠券状态不匹配")
		return
	}
	couponID := couponPtr.ID

	err = q.ResumeCoupon(ctx, couponID)
	if err != nil {
		return
	}
	couponPtr.CouponStatus = string(sqlc.EmCouponStatusPublished)
	couponPtr.Resumed = sqlc.NTimeFromTime(time.Now())
	slog.Infof("1 ResumeCoupon ok")

	return
}

// ExpireCoupons 过期优惠券
func (s *CouponEntityServiceImp) ExpireCoupons(ctx context.Context, q *sqlc.Queries, limit int32) (err error) {
	slog := util.NewContextLogger(ctx, s.slog)

	cnt, err := q.BatchFinishOrCloseCouponSinceFixedDateUseEnded(ctx, limit)
	if err != nil {
		return
	}
	slog.Infof("BatchFinishOrCloseCouponSinceFixedDateUseEnded (%d)条", cnt)

	return
}
